package models

import (
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cast"
	"gorm.io/gorm"
	"hc_server/pkg/file"
	"hc_server/pkg/util"
	"hc_server/routers/response/agentResponse"
	"hc_server/routers/response/transactionManagerResponse"
	"strconv"
	"time"
)

// Agent 代理商表
type Agent struct {
	Model
	AgentName string `json:"agent_name" gorm:"comment:'代理名称'"`
	RealName  string `json:"real_name" gorm:"comment:'真实姓名'"`
	Mobile    string `json:"mobile" gorm:"unique;" comment:"手机号码"`
	Password  string `json:"password" gorm:"comment:'密码'"`
	Sex       int8   `json:"sex" gorm:"comment:'性别 1男 2女'"`
	IdCard    string `json:"id_card" gorm:"comment:'身份证'"`
	AgentNo   string `json:"agent_no" gorm:"comment:'代理商编号'"`
	Avatar    string `json:"avatar" gorm:"comment:'头像'"`
	//AgentRelation string `json:"agent_relation" gorm:"comment:'代理商关系'"`
	BaseAgentId   int    `json:"base_agent_id" gorm:"comment:'所属代理商'"`
	Email         string `json:"email" gorm:"comment:'邮箱'"`
	AccountStatus int8   `json:"account_status" gorm:"comment:'账户状态 1已启用 2未启用'"`
	AuthStatus    int8   `json:"auth_status" gorm:"comment:'认证状态 1已认证 2未认证'"`
	ActivityId    int    `json:"activity_id" gorm:"default:1;comment:'活动政策id'"`
	Type          int8   `json:"type" gorm:"default:0;comment:'代理商类型: 0=代理商 1=机构 2=管理员'"`
}

// AgentExistByID 通过id判断是否存在
func AgentExistByID(id int) (bool, error) {
	var agt Agent
	err := db.Select("id").Where("id = ?", id).First(&agt).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Errorf("此代理不存在: id:%d err:%v", id, err)
		return false, fmt.Errorf("此代理不存在")
	}

	return agt.ID > 0, nil
}

// AgentExistByMobile 通过mobile判断是否存在
func AgentExistByMobile(mobile string) (bool, error) {
	var agt Agent
	err := db.Select("id").Where("mobile = ?", mobile).First(&agt).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Errorf("此代理不存在: mobile:%s err:%v", mobile, err)
		return false, fmt.Errorf("此代理不存在")
	}

	return agt.ID > 0, nil
}

// AgentBaseAgentIdByMobile 通过mobile判断是否存在并返回所属代理商id
func AgentBaseAgentIdByMobile(mobile string) (bool, error) {
	var agt Agent
	err := db.Where("mobile = ?", mobile).First(&agt).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Errorf("此代理不存在: id:%s err:%v", mobile, err)
		return false, fmt.Errorf("此代理不存在")
	}

	return agt.ID > 0, nil
}

// AgentGetFieldsByKeyword 通过字段名获取字段
func AgentGetFieldsByKeyword(id, keyword interface{}) (interface{}, error) {
	var data string
	err := db.Model(&Agent{}).Select(keyword).Where("id = ?", id).Scan(&data).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Error("此代理不存在: id:%d err:%v", id, err)
		return nil, fmt.Errorf("此代理不存在: id:%d err:%v", id, err)
	}

	return data, nil
}

// AgentGetInfoByID 通过id获取详情
func AgentGetInfoByID(id interface{}) (map[string]string, error) {
	agent := new(Agent)
	err := db.Model(&Agent{}).Where("id = ?", id).Scan(&agent).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Error("此代理不存在: id:%d err:%v", id, err)
		return nil, fmt.Errorf("此代理不存在: id:%d err:%v", id, err)
	}
	if agent.ID == 0 {
		return nil, errors.New("此代理不存在")
	}

	// 身份证脱敏处理
	var idCard string
	if len(agent.IdCard) == 18 {
		idCard = agent.IdCard[0:6] + "************" + agent.IdCard[14:]
	}

	return map[string]string{
		"id":            cast.ToString(agent.ID),
		"mobile":        agent.Mobile,
		"sex":           cast.ToString(agent.Sex),
		"idCard":        idCard,
		"agentNo":       agent.AgentNo,
		"accountStatus": cast.ToString(agent.AccountStatus),
		"authStatus":    cast.ToString(agent.AuthStatus),
	}, nil
}

// AgentGetByAgentNo 通过agentNo判断是否存在
func AgentGetByAgentNo(agentNo interface{}) (bool, error) {
	var agent Agent
	err := db.Select("id").Where("agent_no = ?", agentNo, 0).First(&agent).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Errorf("此代理不存在: agent_no:%s err:%v", agentNo, err)
		return false, fmt.Errorf("此代理不存在: agent_no:%s err:%v", agentNo, err)
	}

	return agent.ID > 0, nil
}

// AgentGetInfoByAgentNo 通过agentNo获取详情
func AgentGetInfoByAgentNo(agentNo interface{}) (map[string]string, error) {
	agent := new(Agent)
	err := db.Model(&Agent{}).Where("agent_no = ?", agentNo).Scan(&agent).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Error("此代理不存在: agentNo:%d err:%v", agentNo, err)
		return nil, fmt.Errorf("此代理不存在: agentNo:%d err:%v", agentNo, err)
	}
	if agent.ID == 0 {
		logrus.WithError(err).Errorf("代理商不存在 agent_no: %s", agentNo)
		return nil, errors.New("代理商不存在")
	}

	// 身份证脱敏处理
	var idCard string
	if len(agent.IdCard) == 18 {
		idCard = agent.IdCard[0:6] + "************" + agent.IdCard[14:]
	}

	return map[string]string{
		"id":            cast.ToString(agent.ID),
		"baseAgentId":   cast.ToString(agent.BaseAgentId),
		"mobile":        agent.Mobile,
		"sex":           cast.ToString(agent.Sex),
		"idCard":        idCard,
		"agentNo":       agent.AgentNo,
		"accountStatus": cast.ToString(agent.AccountStatus),
		"authStatus":    cast.ToString(agent.AuthStatus),
	}, nil
}

// AgentGetMaxAgentNo 获取当前最大的代理商编号
func AgentGetMaxAgentNo() string {
	var maxAgentNo string
	db.Model(&Agent{}).Select("MAX(CAST(agent_no AS UNSIGNED)) AS max_agent_no").Scan(&maxAgentNo)
	return maxAgentNo
}

// AgentLogin 代理商登录
func AgentLogin(mobile interface{}, password interface{}) (map[string]string, error) {
	agent := new(Agent)

	err := db.Model(&Agent{}).Where("mobile = ? AND password = ?", mobile, password).Scan(&agent).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Error(fmt.Sprintf("/api/v1/appAgent/login mobile:%s password:%s", mobile, password))
		return nil, fmt.Errorf("获取代理商信息错误: %w", err)
	}
	if agent.ID == 0 {
		return nil, errors.New("账号或密码错误")
	}
	return map[string]string{
		"id":            cast.ToString(agent.ID),
		"mobile":        agent.Mobile,
		"agentName":     agent.AgentName,
		"sex":           cast.ToString(agent.Sex),
		"idCard":        agent.IdCard,
		"agentNo":       "P" + agent.AgentNo,
		"accountStatus": cast.ToString(agent.AccountStatus),
		"authStatus":    cast.ToString(agent.AuthStatus),
	}, nil
}

// AgentRegister 代理商注册
func AgentRegister(agentName, mobile, agentNo, password string, baseAgentId int) (map[string]interface{}, error) {
	agt := &Agent{
		AgentName:     agentName,
		Mobile:        mobile,
		Password:      password,
		AgentNo:       agentNo,
		BaseAgentId:   baseAgentId,
		AccountStatus: 2,
		AuthStatus:    2,
	}
	err := db.Create(agt).Error

	if baseAgentId == 0 {
		//如果上级代理商是管理员那么此字段保存自己的id
		db.Model(&agt).Update("base_agent_id", agt.ID)
	}

	if err != nil {
		logrus.WithError(err).Infof("代理商注册失败: agentName:%s mobile:%s agentNo:%s password:%s", agentName, mobile, agentNo, password)
		return nil, errors.New("注册代理商错误")
	}
	return map[string]interface{}{
		"id": agt.ID,
	}, nil
}

// AgentInfoUpdate 更新代理商信息
func AgentInfoUpdate(id interface{}, mapd map[string]interface{}) error {
	err := db.Model(&Agent{}).Where("id = ?", id).Updates(mapd).Error
	if err != nil {
		logrus.WithError(err).Infof("代理商信息更新失败: id:%s mapd:%s", id, mapd)
		return errors.New("代理商信息更新失败")
	}
	return nil
}

// AgentMerchantAgentList 商户入驻获取代理商列表
func AgentMerchantAgentList(id, pageNum, pageSize interface{}, keyword string) (map[string]interface{}, error) {
	var (
		agents       = make([]*agentResponse.MerchantAgentListResponse, 0)
		count        int64
		conditionSql = fmt.Sprintf("FIND_IN_SET(%d, agent_relations.relation) AND %d <> agent_relations.agent_id", id, id)
		joinSql      = ""
	)

	if len(keyword) > 0 {
		joinSql = fmt.Sprintf("INNER JOIN agents ON agents.id = agent_relations.agent_id AND agent_name LIKE '%s%%'", keyword)
	} else {
		joinSql = fmt.Sprintf("INNER JOIN agents ON agents.id = agent_relations.agent_id")
	}

	db.Model(&AgentRelation{}).
		Select("agents.id,agents.agent_name,CONCAT('P',agents.agent_no) AS agent_no").
		InnerJoins(joinSql).
		Where(conditionSql).
		Limit(cast.ToInt(pageSize)).
		Offset((cast.ToInt(pageNum) - 1) * cast.ToInt(pageSize)).
		Order("agents.created_at DESC").
		Scan(&agents)

	db.Model(&AgentRelation{}).
		Joins(joinSql).
		Where(conditionSql).
		Count(&count)

	return map[string]interface{}{
		"count":  strconv.FormatInt(count, 10),
		"result": agents,
	}, nil
}

// TeamManagerAgentList 团队管理-获取代理商列表
func TeamManagerAgentList(id, pageNum, pageSize interface{}) (map[string]interface{}, error) {
	var (
		results = make([]*agentResponse.TeamManagerAgentListResponse, 0)
		count   int64
	)

	db.Model(&AgentRelation{}).
		Select("agents.id,agents.created_at,agents.agent_name,CONCAT('P',agents.agent_no) AS agent_no,"+
			"COUNT(ar.id) AS agent_team_count,COUNT(s.id) AS salesment_team_count").
		Joins("LEFT JOIN agents ON agents.id = agent_relations.agent_id").
		Joins("LEFT JOIN agent_relations AS ar ON ar.superior_id = agents.id").
		Joins("LEFT JOIN salesmens AS s ON s.agent_id = agents.id").
		Where("FIND_IN_SET(?, agent_relations.relation) AND ? <> agent_relations.agent_id", id, id).
		Group("agent_relations.id").
		Limit(cast.ToInt(pageSize)).
		Offset((cast.ToInt(pageNum) - 1) * cast.ToInt(pageSize)).
		Order("agents.created_at DESC").
		Scan(&results)

	db.Model(&AgentRelation{}).
		Where("FIND_IN_SET(?, relation) AND ? <> id", id, id).
		Count(&count)

	return map[string]interface{}{
		"count":  strconv.FormatInt(count, 10),
		"result": results,
	}, nil
}

// TeamManagerAgentGetInfoByID 通过id获取详情
func TeamManagerAgentGetInfoByID(id interface{}) (*agentResponse.TeamManagerAgentInfoResponse, error) {
	result := new(agentResponse.TeamManagerAgentInfoResponse)

	err := db.Model(&Agent{}).
		Select("agents.id, agents.agent_name, agents.agent_no, agents.mobile AS agent_mobile, agents.email AS agent_mail, "+
			"agents.account_status, agents.auth_status, a.agent_name AS base_team, a.agent_no AS base_team_no, "+
			"ac.name AS activity_name,ac.id AS activity_id,superior.agent_name AS superior_agent,COUNT(DISTINCT agent_relations.id) AS agent_team_count,"+
											"COUNT(DISTINCT sale.id) AS salesment_team_count,rate.type AS activity_type").
		Joins("LEFT JOIN agents AS a ON a.id = agents.base_agent_id").     // 所属代理
		Joins("LEFT JOIN activities AS ac ON ac.id = agents.activity_id"). // 活动政策
		Joins("LEFT JOIN agent_relations AS ar ON ar.agent_id = agents.id").
		Joins("LEFT JOIN agents AS superior ON superior.id = ar.superior_id").                                                           // 上级代理
		Joins("LEFT JOIN agent_relations ON FIND_IN_SET(agents.id,agent_relations.relation) AND agents.id <> agent_relations.agent_id"). // 下级代理
		Joins("LEFT JOIN salesmens AS sale ON sale.agent_id = agents.id").
		Joins("LEFT JOIN agent_rates AS rate ON rate.agent_id = agents.id").
		Group("agents.id,a.id,ac.id,superior.id,rate.id").
		Where("agents.id = ?", id).
		Scan(&result).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Error("此代理不存在: id:%d err:%v", id, err)
		return nil, fmt.Errorf("此代理不存在")
	}

	result.BaseTeamNo = "P" + result.BaseTeamNo
	result.AgentNo = "P" + result.AgentNo

	return result, nil
}

// AgentGetRateById 通过代理id获取此代理上级费率与结算信息
func AgentGetRateById(id interface{}) (*agentResponse.RateAgentRateInfoResponse, error) {
	var result = new(agentResponse.RateAgentRateInfoResponse)

	err := db.Model(&AgentRelation{}).
		Select("rate.wechat_min,rate.wechat_max,rate.alipay_min,rate.alipay_max,rate.yun_pay_low_min,"+
			"rate.yun_pay_low_max,rate.yun_pay_high_min,rate.yun_pay_high_max,rate.debit_card_min,rate.debit_card_max,"+
			"rate.debit_card_capping_min,rate.debit_card_capping_max,rate.credit_card_min,rate.credit_card_max,"+
			"slt.d0_settlement_rate_min,slt.d0_settlement_rate_max,slt.d0_settlement_min,slt.d0_settlement_max,"+
			"slt.d1_settlement_rate_min,slt.d1_settlement_rate_max,slt.d1_settlement_min,slt.d1_settlement_max,"+
			"slt.withdrawal_rate_min,slt.withdrawal_rate_max,slt.withdrawal_min,slt.withdrawal_max").
		Joins("LEFT JOIN agents ON agents.id = agent_relations.superior_id").
		Joins("LEFT JOIN agent_rates AS rate ON rate.agent_id = agent_relations.superior_id").
		Joins("LEFT JOIN agent_settlement_rates AS slt ON slt.agent_id = agent_relations.superior_id").
		Where("agent_relations.agent_id = ?", id).
		Scan(&result).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.WithError(err).Error("此代理不存在: id:%d err:%v", id, err)
		return nil, errors.New("此代理不存在")
	}

	return result, nil
}

// TransactionManagerTransactionList 获取商户交易列表
func TransactionManagerTransactionList(merchantId, index, size int) (map[string]interface{}, error) {
	var result = make([]*transactionManagerResponse.TransactionListResponse, 0)
	var count int64

	db.Select("platform AS type,amount,created_at AS time").Model(&MerchantOrder{}).
		Where("merchant_id = ?", merchantId).
		Limit(size).
		Offset((index - 1) * size).
		Scan(&result)
	db.Model(&MerchantOrder{}).Where("merchant_id = ?", merchantId).Count(&count)

	return map[string]interface{}{
		"list":  result,
		"count": count}, nil
}

// GetAgentTeamList 获取代理团队列表
func GetAgentTeamList(agentId, typed interface{}) []map[string]interface{} {
	//typed 1=当日 2=昨日 3=本月
	var timeStr string
	switch cast.ToInt(typed) {
	case 2:
		timeStr = fmt.Sprintf("created_at BETWEEN '%s' AND '%s'", time.Now().AddDate(0, 0, -1).Format("2006-01-02"), time.Now().Format("2006-01-02"))
	case 3:
		timeStr = fmt.Sprintf("created_at >='%s'", time.Now().Format("2006-01"))
	default:
		timeStr = fmt.Sprintf("created_at >='%s'", time.Now().Format("2006-01-02"))
	}

	amountSql := fmt.Sprintf(`
                      (SELECT COALESCE(SUM(merchant_orders.amount), 0) 
                       FROM merchant_relations 
                       LEFT JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id AND merchant_orders.%s  
                       WHERE FIND_IN_SET( agents.id, merchant_relations.relation ) ) AS amount`, timeStr)
	merchantCountSql := fmt.Sprintf(`
                      (SELECT COUNT(merchants.id) 
                       FROM merchant_relations 
                       LEFT JOIN merchants ON merchants.id = merchant_relations.merchant_id AND merchants.%s
                       WHERE FIND_IN_SET(agents.id, merchant_relations.relation)) AS merchant_count`, timeStr)

	sql := fmt.Sprintf(`SELECT agents.id,agents.agent_name,
       %s,  
       %s
        FROM agent_relations
        LEFT JOIN agents ON agent_relations.agent_id = agents.id 
        WHERE FIND_IN_SET('%d', agent_relations.relation) > 0 AND agents.deleted_at IS NULL`, amountSql, merchantCountSql, agentId)
	var result = make([]map[string]interface{}, 0)
	db.Raw(sql).Scan(&result)
	return result
}

// GetAgentPerformanceInfo 获取业绩信息
func GetAgentPerformanceInfo(agentId, typed interface{}) (*agentResponse.GetAgentPerformanceInfo, error) {
	var timeStr string
	switch cast.ToInt(typed) {
	case 2:
		//昨日
		timeStr = fmt.Sprintf(`created_at BETWEEN '%s' AND '%s'`, time.Now().AddDate(0, 0, -1).Format("2006-01-02"), time.Now().Format("2006-01-02"))
	case 3:
		//本月
		timeStr = fmt.Sprintf(`created_at >='%s'`, time.Now().Format("2006-01"))
	case 4:
		//上月
		timeStr = fmt.Sprintf(`created_at BETWEEN '%s' AND '%s'`, time.Now().AddDate(0, -1, 0).Format("2006-01-02"), time.Now().Format("2006-01-02"))
	case 5:
		//历史
		timeStr = fmt.Sprintf(`created_at <='%s'`, time.Now().AddDate(0, 0, 1).Format("2006-01-02"))
	default:
		//今日
		timeStr = fmt.Sprintf(`created_at >='%s'`, time.Now().Format("2006-01-02"))
	}

	var result *agentResponse.GetAgentPerformanceInfo

	db.Model(&Agent{}).Select("COUNT(DISTINCT merchant_relations.id) AS merchant_num,COUNT(DISTINCT agent_relations.id) AS agent_num,COUNT(DISTINCT devices.id) AS binding_num,COUNT(DISTINCT salesmens.id) AS salesman_num").
		Joins("LEFT JOIN agent_relations ON FIND_IN_SET(agents.id,agent_relations.relation) AND agent_relations."+timeStr).
		Joins("LEFT JOIN merchant_relations ON FIND_IN_SET(agents.id,merchant_relations.relation) AND merchant_relations."+timeStr).
		InnerJoins("INNER JOIN merchant_relations AS mr ON FIND_IN_SET(agents.id,mr.relation)").
		InnerJoins("INNER JOIN devices ON devices.merchant_id = mr.merchant_id AND devices."+timeStr).
		InnerJoins("INNER JOIN agent_relations AS ar ON FIND_IN_SET(agents.id,ar.relation)").
		InnerJoins("INNER JOIN salesmens ON salesmens.agent_id = ar.agent_id AND salesmens."+timeStr).
		Where("agents.id = ?", agentId).Scan(&result)

	db.Model(&MerchantRelation{}).Select("COALESCE( SUM( merchant_orders.amount ), 0 ) AS amount,COUNT(merchant_orders.id) AS pay_num").
		Joins("LEFT JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id AND merchant_orders."+timeStr).
		Where("FIND_IN_SET( ?, merchant_relations.relation )", agentId).Scan(&result)

	return result, nil
}

// AgentMyInfo 获取app我的页面数据
func AgentMyInfo(agentId int) (*agentResponse.GetAgentMyInfo, error) {
	var result *agentResponse.GetAgentMyInfo
	err := db.Model(&Agent{}).Select("agents.agent_name,agents.avatar,agents.auth_status,CONCAT('P',agents.agent_no) AS agent_no").
		Where("agents.id = ?", agentId).Scan(&result).Error
	if err != nil {
		return nil, err
	}
	if len(result.Avatar) > 0 {
		result.Avatar = file.GetAgentFileFullUrl(cast.ToString(agentId), result.Avatar)
	}
	return result, nil
}

// MyCenterInfo 获取app我的页面数据
func MyCenterInfo(agentId int) (any, error) {
	var result *agentResponse.GetMyCenterInfo
	err := db.Model(&Agent{}).Select("agents.agent_name,agents.avatar,agents.auth_status,CONCAT('P',agents.agent_no) AS agent_no,agents.mobile").
		Where("agents.id = ?", agentId).Scan(&result).Error
	if err != nil {
		return nil, err
	}
	if len(result.Avatar) > 0 {
		result.Avatar = file.GetAgentFileFullUrl(cast.ToString(agentId), result.Avatar)
	}
	if len(result.Mobile) > 0 {
		result.Mobile = util.DesensitizePhoneNumber(result.Mobile)
	}
	return result, nil
}

// AgentUploadAvatar 上传照片
func AgentUploadAvatar(agentId int, avatar string) error {
	return db.Model(&Agent{}).Where("id = ?", agentId).Update("avatar", avatar).Error
}

// AgentMyPasswordEdit 修改密码
func AgentMyPasswordEdit(agentId int, opwd, npwd string) error {
	err := db.Model(&Agent{}).Where("id = ? AND password = ?", agentId, opwd).Update("password", npwd).Error
	if err != nil {
		return errors.New("账号或密码错误")
	}
	return nil
}

func AgentMyInfoDelete(agentId int) error {
	var temp *Agent
	db.Model(&Agent{}).Where("id = ?", agentId).Scan(&temp)
	db.Delete(&temp)
	return db.Delete(&temp).Error
}
